﻿using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Effects;
using System.Windows.Shapes;

namespace Heyo.Controls.Animations
{
    public class AnimationLayer : ClippingBorder
    {
        /// <summary>
        /// 动画速度
        /// </summary>
        [Category("Animation")]
        public double AnimationSpeed { get; set; } = 2;

        /// <summary>
        /// 阴影动画
        /// </summary>
        [Category("Animation")]
        public bool ShadowAnim { get; set; } = false;

        /// <summary>
        /// 水波反馈
        /// </summary>
        [Category("Animation")]
        public bool MouseDownWave { get; set; } = true;

        
        [Category("Animation")] public static readonly DependencyProperty MouseOnBrushProperty = DependencyProperty.Register(
            "MouseOnBrush", typeof(Brush), typeof(AnimationLayer), new PropertyMetadata(new SolidColorBrush(Color.FromArgb(90, 0, 0, 0)), ((o, args) =>
            {
                ((AnimationLayer) o)._rectMouseEnterBg.Fill = (Brush)args.NewValue;} )));

        public Brush MouseOnBrush
        {
            get => (Brush) GetValue(MouseOnBrushProperty);
            set => SetValue(MouseOnBrushProperty, value);
        }

        /// <summary>
        /// 鼠标移入移出动画
        /// </summary>
        public bool MouseEnterAnimation
        {
            get => (bool)GetValue(MouseEnterAnimationProperty);
            set
            {
                OnPropertyChanged(new DependencyPropertyChangedEventArgs(MouseEnterAnimationProperty, Shadow, value));
                SetValue(MouseEnterAnimationProperty, value);
            }
        }

        public static readonly DependencyProperty MouseEnterAnimationProperty =
            DependencyProperty.Register(
                "MouseEnterAnimation",
                typeof(bool),
                typeof(AnimationLayer),
                new PropertyMetadata(true)
            );
        [Category("Appearance")]
        public bool Shadow
        {
            get => (bool)GetValue(ShadowProperty);
            set => SetValue(ShadowProperty, value);
        }

        public static readonly DependencyProperty ShadowProperty =
            DependencyProperty.Register(
                "Shadow",
                typeof(bool),
                typeof(AnimationLayer),
                new PropertyMetadata(false, ShadowPropertyChanged)
            );



        protected Canvas CanvasAnimation { get; } = new Canvas()
        {
            Opacity = 1,
            Background = new SolidColorBrush(Colors.Transparent)
        };
        private readonly Rectangle _rectMouseEnterBg = new Rectangle()
        {
            Opacity = 0,
            Fill = new SolidColorBrush(Colors.Bisque)
        };
        protected readonly DoubleAnimation DepthAnim = new DoubleAnimation();
        protected readonly DoubleAnimation RadiusAnim = new DoubleAnimation();

        //private readonly PowerEase _easeFunction = new PowerEase() { EasingMode = EasingMode.EaseInOut, Power = 4 };

        private const double UpDepth = 8; //抬升时高度
        private const double UpRadius = 3; //抬升时阴影半径倍率
        private const double DownDepth = 1; //下降时高度
        private const double DownRadius = 3; //下降时阴影半径(会随自适应改变,默认值为3)
        private const int ShadowDirection = 260;
        private const double ShadowOpacity = 0.3;

        public AnimationLayer()
        {
            Loaded += MaterialCard_Loaded;
            this.AddVisualChild(CanvasAnimation);
            UseLayoutRounding = true;


            DepthAnim.EasingFunction =
                RadiusAnim.EasingFunction = new PowerEase() { EasingMode = EasingMode.EaseOut, Power = 3 };


            DepthAnim.SpeedRatio = RadiusAnim.SpeedRatio = AnimationSpeed * 2;


            MouseEnter += (s, e) => { BeginMouseEnterAnim(e); };
            MouseLeave += (s, e) =>
            {
                BeginMouseLeaveAnim(e);
            };
            MouseDown += (s, e) =>
            {
                if (Shadow && ShadowAnim)
                {
                    BeginShadowAnimation(DownDepth, DownRadius);
                }
            };
            MouseUp += (s, e) =>
            {
                if (Shadow && ShadowAnim)
                {
                    BeginShadowAnimation(UpDepth, DownRadius * UpRadius);
                }
            };

            CanvasAnimation.ClipToBounds = true;
            var bgBinding = new Binding
            {
                Source = this,
                Path = new PropertyPath(BackgroundProperty.Name)
            };
            CanvasAnimation.SetBinding(BackgroundProperty, bgBinding);
            CanvasAnimation.SizeChanged += (s, e) =>
            {
                _rectMouseEnterBg.Height =  e.NewSize.Height;
                _rectMouseEnterBg.Width =  e.NewSize.Width;
            };
            CanvasAnimation.Children.Add(_rectMouseEnterBg);
        }
        protected override void OnRender(DrawingContext dc)
        {
            OnApplyChildClip();
            base.OnRender(dc);
        }

        protected override void OnApplyChildClip()
        {
            ClipRect.RadiusX = ClipRect.RadiusY = Math.Max(0.0, CornerRadius.TopLeft - (BorderThickness.Left * 0.5));
            var rect = new Rect(RenderSize);
            rect.Height -= (BorderThickness.Top + BorderThickness.Bottom);
            rect.Width -= (BorderThickness.Left + BorderThickness.Right);
            ClipRect.Rect = rect;
            CanvasAnimation.Clip = ClipRect;
        }
        private void MaterialCard_Loaded(object sender, RoutedEventArgs e)
        {
            _rectMouseEnterBg.Fill = MouseOnBrush;
        }



        private void BeginMouseEnterAnim(System.Windows.Input.MouseEventArgs e)
        {
            if (!MouseEnterAnimation) return;

            var animation = new DoubleAnimation()
            {
                To = 0.3,
                SpeedRatio = AnimationSpeed * 2,
                EasingFunction = new PowerEase() { EasingMode = EasingMode.EaseOut, Power = 4 }
            };

            _rectMouseEnterBg.BeginAnimation(Canvas.OpacityProperty, animation);

            if (!Shadow || !ShadowAnim) return;
            if (Effect == null && Shadow && ShadowAnim)
            {
                Effect = new DropShadowEffect()
                {
                    BlurRadius = DownRadius,
                    Opacity = ShadowOpacity,
                    ShadowDepth = DownDepth,
                    Direction = ShadowDirection
                };
            }


            BeginShadowAnimation(UpDepth, DownRadius * UpRadius);
        }

        private void BeginMouseLeaveAnim(System.Windows.Input.MouseEventArgs e)
        {
            if (!MouseEnterAnimation) return;

            var ca = new DoubleAnimation()
            {
                To = 0,
                SpeedRatio = AnimationSpeed * 1.5,
                EasingFunction = new PowerEase() { EasingMode = EasingMode.EaseOut, Power = 4 }
            };
            _rectMouseEnterBg.BeginAnimation(Canvas.OpacityProperty, ca);

            if (Shadow && ShadowAnim)
            {
                BeginShadowAnimation(DownDepth, DownRadius);
            }

        }

        private void BeginShadowAnimation(double depth, double radius)
        {
            DepthAnim.To = depth;
            RadiusAnim.To = radius;
            ((DropShadowEffect)Effect).BeginAnimation(DropShadowEffect.ShadowDepthProperty, DepthAnim);
            ((DropShadowEffect)Effect).BeginAnimation(DropShadowEffect.BlurRadiusProperty, RadiusAnim);
        }

        private static void ShadowPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            var card = (WaveClick)sender;
            if (!(bool)args.NewValue)
            {
                card.Effect = null;
            }
        }


        //以下操作是为了显示出BackgroundCanvas
        protected override int VisualChildrenCount => base.VisualChildrenCount + 1;

        protected override Visual GetVisualChild(int index)
        {
            return index == 0 ? CanvasAnimation : base.GetVisualChild(index - 1);
        }

        protected override Size MeasureOverride(Size availableSize)
        {
            availableSize.Height -= (Padding.Bottom + Padding.Top);// + BorderThickness.Top + BorderThickness.Bottom;
            availableSize.Width -= (Padding.Left + Padding.Right);// + BorderThickness.Left + BorderThickness.Right;

            for (var i = 0; i < VisualChildrenCount; i++)
            {
                if (GetVisualChild(i) is UIElement element)
                    element.Measure(availableSize);
            }

            return Child?.DesiredSize ?? CanvasAnimation.DesiredSize;
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            var arrangeRect = new Rect
            {
                Width = finalSize.Width - Padding.Left - Padding.Right,
                Height = finalSize.Height - Padding.Top - Padding.Bottom,
                Location = new Point(Padding.Left, Padding.Top)
            };
            Child?.Arrange(arrangeRect);

            var arrangeRect2 = new Rect
            {
                Width = finalSize.Width,
                Height = finalSize.Height,
                Location = new Point(BorderThickness.Left, BorderThickness.Top)
            };
            CanvasAnimation.Arrange(arrangeRect2);
            //for (var i = 0; i < VisualChildrenCount; i++)
            //{
            //    if (GetVisualChild(i) is UIElement element)
            //        element.Arrange(arrangeRect);
            //}

            return finalSize;
        }
    }
}
